/**
 * 这里主要演示调用其它言语函数，和使用不安全函数
 * rust-script -d libc -d encoding_rs 20.3_call_unsafe_function.rs
 */

use std::ffi::CString;
use encoding_rs::GBK;
use libc::{c_char, c_int};
// 在 Rust 中声明 C 的 abs 函数
extern "C" {
    fn abs(x: i32) -> i32;
}
extern "C" {
    // 定义C语言的printf函数
    //#[link(name = "c")]
    fn printf(format: *const c_char, ...)-> c_int;
}

fn main() {
    //1.0 直接调用 C 的 abs 函数，无需任何前置条件
    call_c_abs();

    //1.1 调用C语言函数，需要用到C语言环境
    call_c_function();   // 此处注释掉，因为需要用到C语言环境

    //2.0 不安全函数例子
    //不安全函数例子-被标记为unsafe的函数，可以执行不安全的操作,但必须放在unsafe块中执行
    unsafe {dangerous()};

}

fn call_c_abs(){
    let number = -42;
    let absolute_value = unsafe { abs(number) };
    println!("调用C的abs:{}的绝对值= {}", number, absolute_value);
}

fn call_c_function() {
    // 创建一个C字符串
    let format = CString::new("%s %d\n").unwrap();
    
    // 1. 原始UTF-8字符串
    let utf8_message = "调用C的printf:C语言，我来了！这是发自一个rust的程序的消息";
    
    // 2. 将UTF-8转换为GBK
    let (gbk_bytes, _, _) = GBK.encode(utf8_message);
    
    // 3. 创建一个GBK编码的CString
    // 注意：需要去掉末尾的null字节，因为CString会自动添加
    let gbk_bytes_without_null = if gbk_bytes.ends_with(&[0]) {
        &gbk_bytes[..gbk_bytes.len() - 1]
    } else {
        &gbk_bytes[..]
    };
    let message = CString::new(gbk_bytes_without_null).unwrap();
    let number = 114975;
    // 调用C语言的printf函数
    unsafe {
        //这样打印会乱码，如何不乱码了？
        printf(format.as_ptr(), message.as_ptr(), number);
    }
}

//不安全函数例子        
//至于内容是不是安全的，我们不关心。重点是，这个函数是被标记为unsafe的
unsafe fn dangerous() {
    println!("我是一个不安全的函数,因此不需要unsafe块就可以执行其它不安全的操作。");
    play();
}

unsafe fn play() {
    //注意，本函数基本上和另外一个地方的例子一模一样，但是此处居然不触发致命错误，为什么？
    //  如果game的值是英文，那么会有很大概率触发异常，但是如果game的内容是中文，则不会触发致命错误。
    //  为什么?
    //let game = Box::new(String::from("fuck dog"));  //这个有很大概况触发致命错误
    let game = Box::new(String::from("跑步、捉迷藏、踢足球、下棋"));  //这个不会错误，为什么？
    let raw_game = Box::into_raw(game);
    println!("游戏内容: {:?}", *raw_game);
    drop(Box::from_raw(raw_game));
    println!("游戏内容(来自Box指针): {:?}", *raw_game);
}